home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_03_05 / 3n05036a < prev    next >
Text File  |  1992-03-09  |  8KB  |  279 lines

  1. /*******************************************************
  2.    File dllparam.c
  3.  
  4.    Demonstration of Visual Basic to DLL interface
  5.  
  6.    Written By Daniel Appleman
  7.    Copyright (c) 1992, by Desawre - All rights reserved
  8.  
  9. ********************************************************/
  10.  
  11. #define LINT_ARGS
  12. #define NOMINMAX
  13. #define OEMRESOURCE
  14. #define NOREGION
  15. #define NOWH
  16. #define NORASTEROPS
  17. #define NOMETAFILE
  18. #define NOCLIPBOARD
  19. #define NOOPENFILE
  20. #define NOKANJI
  21. #define NOSOUND
  22. #define NOCOMM
  23. #define NOGDICAPMASKS
  24. #define NOVIRTUALKEYCODES 
  25.  
  26. #include "windows.h"
  27. #include "\windows\vb\custom\vbapi.h"
  28. #include "stdlib.h"
  29. #include "string.h"
  30.  
  31. HANDLE modulehandle;    /* module handle for library */
  32.  
  33. BOOL FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg,
  34.                         WORD cbHeap, LPSTR lpszCmdLine)
  35. {
  36.    modulehandle = hModule;
  37.    return(1);
  38. }
  39.  
  40. VOID FAR PASCAL WEP (int bSystemExit)
  41. {   return;  }
  42.  
  43. char tbuf[80];
  44. #define MSGBOX(s) MessageBox(GetFocus(), (LPSTR)tbuf, \
  45.                     (LPSTR)s, MB_OK)
  46.  
  47. /* Utility function to convert floating point to string
  48.  * Quick and dirty - as the DLL library does not have
  49.  * function gcvt  */
  50. fToString(double d, char *t)
  51. {
  52.    int x;
  53.    static int decimalvar, signvar;
  54.    char *buffer;
  55.    buffer = fcvt(d,5,&decimalvar, &signvar);
  56.    if(signvar) *t++ = '-';
  57.    for(x=0; x<decimalvar && *buffer; x++) *t++ = *buffer++;
  58.    if(*buffer) *t++ = '.';
  59.    while(*buffer) *t++ = *buffer++;
  60.    *t = '\0';
  61. }
  62.  
  63. /* These function demonstrates passing numeric
  64.  * variables by value, and returning numeric variables. 
  65.  * The MessageBox statement in each routine shows the
  66.  * value of the variable received. */
  67. int FAR PASCAL ReceivesInteger(int x)
  68. {
  69.    itoa(x, tbuf, 10); /* Place value in temporary buffer */
  70.    MSGBOX("ReceivesInteger");
  71.    return(x);
  72. }
  73.  
  74. long FAR PASCAL ReceivesLong(long y)
  75. {
  76.    ltoa(y, tbuf, 10); /* Place value in temporary buffer */
  77.    MSGBOX("ReceivesLong");
  78.    return(y);
  79. }
  80.  
  81. float FAR PASCAL ReceivesSingle(float f)
  82. {
  83.    fToString((double)f, tbuf);
  84.    MSGBOX("ReceivesSingle");
  85.    return(f);
  86. }
  87.  
  88. double FAR PASCAL ReceivesDouble(double d)
  89. {
  90. /* Refer to the article text for some important notes
  91.  * relating to the declaration of functions that
  92.  * receive or return double parameters.  */
  93.    fToString(d, tbuf);
  94.    MSGBOX("ReceivesDouble");
  95.    return(d);
  96. }
  97.  
  98. /*
  99.  * These functions demonstrate passing numeric
  100.  * variables by reference.  Note how the DLL function
  101.  * can modify the variable used by VB.  These
  102.  * particular examples are defined as VOID to be used
  103.  * by SUB declarations in VB.  One could just as easily
  104.  * had these return results as done in the examples
  105.  * above.  */
  106.  
  107. VOID FAR PASCAL Add5ToInteger(int FAR *x)
  108. {  *x = (*x) + 5;  }
  109. VOID FAR PASCAL Add5ToLong(long FAR *y)
  110. {  *y = (*y) + 5;  }
  111. VOID FAR PASCAL Add5ToSingle(float FAR *f)
  112. {  *f = (*f) + 5;  }
  113. VOID FAR PASCAL Add5ToDouble(double FAR *d)
  114. {  *d = (*d) + 5;  }
  115.  
  116. /* Currency is a special 8 byte data type. 
  117.  * Fortunately, Microsoft C (and probably others) can
  118.  * pass structures as parameters by value, and return
  119.  * them.  You'll need to make sure that your compiler
  120.  * uses the Microsoft C calling convention on
  121.  * structures for this to work.  In practice, you will
  122.  * need to build your own complete library of currency
  123.  * data type math to use this data type.  Refer to the
  124.  * article text for details. */
  125.  
  126. /* Currency data type structure */
  127. typedef struct currencystruct {
  128.    char cbuf[8];
  129. } currency;
  130.  
  131. /* This example shows passing a currency variable by
  132.  * value, and returning a currency value */
  133. currency FAR PASCAL ReceivesCurrency(currency curr)
  134. {
  135.    double tres = 0, factor = 1, tval;
  136.    LPSTR tptr;
  137.    short x;
  138.  
  139. /* This currency variable is in base 10 with 4 digits
  140.  * to the right of the decimal point */
  141.  
  142. /* This conversion (for display purposes) involves a
  143.  * loss of precision and does not handle negative
  144.  * numbers */
  145.    for(x=0; x<8; x++) { /* Convert currency to double */
  146.       tval = (double)((WORD)curr.cbuf[x]);
  147.       tres+= tval*factor;
  148.       factor *=256;
  149.       }
  150.    tres/=10000;   /* Number is fixed 4 digit precision,
  151.                     divide to obtain the actual value */
  152.    fToString(tres, tbuf);
  153.    MSGBOX("ReceivesCurrency");
  154.    return(curr);
  155. }
  156.  
  157. /* This example is call-by-reference. */
  158. void FAR PASCAL AddPennyToCurrency(currency FAR *curptr)
  159. {
  160.    short x;
  161.    WORD temp, toadd;
  162.  
  163. /* This currency variable is in base 10 with 4 digits
  164.  * to the right of the decimal point */
  165.  
  166. /* Now you can use whatever math routines you have to
  167.  * maniuplate this buffer - consider this trivial 'add
  168.  * penny' algorithm */
  169.    toadd = 100;   /* 1 penny in this scale */
  170.    for(x=0; x<8 && toadd; x++) {
  171.       temp = curptr->cbuf[x];
  172.       temp+=toadd;
  173.       if(temp>=256) {
  174.          temp-=256;  toadd=1; /* continue with carry */
  175.          }
  176.       else toadd=0;  /* Finished with the addition */
  177.       curptr->cbuf[x] = temp;
  178.       }
  179. }
  180.  
  181. /* Method used for most API calls.  VB passes a null
  182.  * terminated string */
  183. VOID FAR PASCAL ReceivesString(LPSTR tptr)
  184. {/* Warning - it's not a copy despite the
  185.   * byval part in the declaration */
  186.    MSGBOX("ReceivesString");
  187. }
  188.  
  189. /* This example shows how a string can be modified - as
  190.  * long as you don't go beyond the space allocated */
  191. VOID FAR PASCAL ChangesString(LPSTR tptr)
  192. {/* Warning on overwriting null!!! */
  193.    if (*tptr) *tptr = '!';
  194. }
  195.  
  196. /* This example shows how you can pass Visual Basic
  197.  * strings to a DLL, but the DLL must be linked with
  198.  * VBAPI.LIB - part of the VB control development kit. */
  199. VOID FAR PASCAL ReceivesVBString(HLSTR sptr)
  200. {
  201.    LPSTR tptr;
  202.    int vbstrlen;
  203.    WORD x;
  204.    vbstrlen=VBGetHlstrLen(sptr); /* Get len of VB string */
  205.    tptr = VBDerefHlstr(sptr); /* Get ptr to VB string */
  206.    for(x=0; x<vbstrlen && x<sizeof(tbuf)-1; x++)
  207.       tbuf[x] = *tptr++;
  208.    tbuf[x] = '\0';   /* Null terminate the string */
  209.    /* Remember - VB strings can contain NULLs */
  210.    MSGBOX("ReceivesVBString");
  211. }
  212.  
  213. /* This example shows how you can change a string that
  214.  * was passed as a parameter in a DLL.  No length
  215.  * restrictions apply when using this technique (other
  216.  * than the usual VB string length limits */
  217. VOID FAR PASCAL ChangesVBString(HLSTR sptr)
  218. {
  219.    VBSetHlstr((HLSTR FAR *)&sptr,(LPSTR)"Any Length OK",13);
  220. }
  221.  
  222. /* This example shows how you can return a VB string
  223.  * from a DLL.  Note - this technique is not
  224.  * documented, and while it does seem to work, there is
  225.  * no guarantee that it will work under future versions
  226.  * of VB */
  227. HLSTR FAR PASCAL ReturnsVBString()
  228. {
  229.    char *a = "This string is created in the DLL";
  230.    return(VBCreateHlstr((LPSTR)a,strlen(a)));
  231. }
  232.  
  233. typedef struct usertypestruct {
  234.    int a;   int b;
  235.    int c;   int d;
  236.    HLSTR hs;
  237. } usertype;
  238.  
  239. /* Call by reference only */
  240. VOID FAR PASCAL ReceivesUserType(usertype FAR *u)
  241. {
  242.    wsprintf((LPSTR)tbuf,
  243.             (LPSTR)"usertype contains %d %d %d %d",
  244.             u->a, u->b, u->c, u->d);
  245.    MSGBOX("ReceivesUserType");
  246. }
  247.  
  248. /* VB strings in a user defined type can be accessed. 
  249.  * If not initialized, they may be null (though I have
  250.  * never actually seen this - see article text), in
  251.  * which case the DLL can create the string - otherwise
  252.  * the DLL should use VBSetHlstr().  */
  253. VOID FAR PASCAL AddUserString(usertype FAR *u)
  254. {
  255.    if(!u->hs)
  256.    /* Documentation suggests this case may be possible */
  257.       u->hs = VBCreateHlstr((LPSTR)"New string here!",16);
  258.    else
  259.       VBSetHlstr(&u->hs, (LPSTR)"Replaced string", 15);
  260. }
  261.  
  262. /* Array of integers - Be careful not to exceed the limit of the array!
  263.  * This technique can be used on all numeric data types.
  264.  * Note the special calling sequence in the VB example.
  265.  * It will not work on strings. */
  266. VOID FAR PASCAL ReceivesIntArray(int FAR *iptr)
  267. {
  268.    wsprintf((LPSTR)tbuf,
  269.             (LPSTR)"1st 4 entries are %d %d %d %d",
  270.             *(iptr), *(iptr+1), *(iptr+2), *(iptr+3));
  271.    MSGBOX("ReceivesIntArray");
  272. }
  273.  
  274. /* CDK-oriented stuff */
  275. HWND FAR PASCAL GetControlHwnd(HCTL